<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>
<head>
	<title>Real Time Syntax Highlighting Code Editor JavaScript</title>
	<link type="text/css" rel="stylesheet" href="rtsh-javascript.css" />
	<script type="text/javascript" src="rtsh.js"></script>
	<script type="text/javascript">
	RTSH.language = 'javascript';
	</script>
</head>

<!-- no line break between body and pre -->
<body id="ffedt"><pre id="ieedt">/*
Real Time Syntax Highlighting JS - RTSHJS v0.76

You can use and modify this code as you want. 
Just keep my credits somewhere around. Thanks.

Fernando M.A.d.S. - fermads@gmail.com

http://syntaxhighlighting.blogspot.com/2006/08/real-time-syntax-highlighting.html
*/

RTSH = {
	range : null,
	language : null,

	// set initial vars and start sh
	initialize : function() {
		this.detect();
		chars = '|13|32|191|57|48|187|188|'; // charscodes that fires syntax highlighting
		cc = '\xad'; // control char
		if(browser.ff) { // FF
			editor = document.getElementById('ffedt');
			document.designMode = 'on';
			document.addEventListener('keydown', this.keyHandler, true);
			document.body.focus();
		}
		else if(browser.ie) { // IE
			editor = document.getElementById('ieedt');
			editor.contentEditable = 'true';
			document.onkeydown = this.keyHandler;
			//editor.blur();
		}
		else {
			// TODO: textarea without syntax highlighting for non supported browsers
			alert('your browser is not supported at the moment');
			return;
		}
		this.syntaxHighlight(1);
		window.scroll(0,0);
	},

	// detect browser, for now IE and FF only
	detect : function() {
		browser = { ie:false, ff:false };
		if(navigator.appName.indexOf("Microsoft") != -1) browser.ie = true;
		else if (navigator.appName == "Netscape") browser.ff = true;
	},

	// receive key bindings
	keyHandler : function(evt) {
		evt = (evt) ? evt : (window.event) ? event : null;
	  	if(evt) {
	    	charCode = (evt.charCode) ? evt.charCode : ((evt.keyCode) ? evt.keyCode : ((evt.which) ? evt.which : 0));
			// Syntax highlighting occurs every time one of charcodes inside var 'chars' is pressed
		    if((chars.indexOf('|'+charCode+'|')!=-1) && (!evt.ctrlKey && !evt.altKey)) {
			 	RTSH.syntaxHighlight();
			  	RTSH.findString();
			}
			else if(charCode==90 && evt.ctrlKey) { // kill undo, it does not work anyway
				evt.returnValue = false; //IE
				if(browser.ff)evt.preventDefault(); //FF
			}
		}
	},

	// put cursor back to its original position after every parsing
	findString : function() {
		if(browser.ff) { // FF
			self.find(cc);
		}
		if(browser.ie) { // IE
		    range = self.document.body.createTextRange();
			strFound = range.findText(cc);
		   	if (strFound) range.select();
		}
	},

	// syntax highlighting parser
	syntaxHighlight : function() {
		if(browser.ff) { // FF
			//document.execCommand("inserthtml", false, cc);
			window.getSelection().getRangeAt(0).insertNode(document.createTextNode(cc));
			x = editor.innerHTML;
			x = x.replace(/&lt;br&gt;/g,'\n');
			x = x.replace(/&lt;.*?&gt;|&lt;\/.*?&gt;/g,''); 	
			x = x.replace(/\n/g,'&lt;br&gt;');			
		}
		else if(browser.ie) { // IE
			if(!arguments[0])document.selection.createRange().text = cc;
			x = editor.innerHTML;
			x = x.replace(/&lt;P&gt;/g,'\n');
			x = x.replace(/&lt;\/P&gt;/g,'\r');
			x = x.replace(/&lt;\/?.*?&gt;/g,'');
			x = '&lt;P&gt;'+x;
			x = x.replace(/\n/g,'&lt;P&gt;');
			x = x.replace(/\r/g,'&lt;\/P&gt;');
			x = x.replace(/(&lt;P&gt;)+/,'&lt;P&gt;');
			x = x.replace(/&lt;P&gt;&lt;\/P&gt;/g,'&lt;P&gt;&nbsp;&lt;\/P&gt;');			
		}

		for(i=0;i&lt;languages[this.language].length;i++) 
			x = x.replace(languages[this.language][i],languages[this.language][i+1]);
		
		editor.innerHTML = '&lt;pre&gt;'+x+'&lt;/pre&gt;';
	},
	
	// transform syntax highlighted code to original code
	plainText : function() { 
		code = document.getElementsByTagName('body')[0].innerHTML;
		code = code.replace(/&lt;br&gt;/gi,'\n');
		code = code.replace(/&lt;\/p&gt;/gi,'\r');		
		code = code.replace(/&lt;p&gt;/gi,'\n');
		code = code.replace(/&nbsp;/gi,'');
		code = code.replace(/\xad/g,'');
		code = code.replace(/&lt;.*?&gt;/g,'');
		code = code.replace(/&lt;/g,'&lt;');
		code = code.replace(/&gt;/g,'&gt;');
		return code;
	}	
}

// language specific regular expressions
// TODO: distribute languages into specific [language].js
languages = { 
	java : [
	/([\"\'].*?[\"\'])/g,'&lt;s&gt;$1&lt;/s&gt;', // strings
	/(abstract|continue|for|new|switch|assert|default|goto|package|synchronized|boolean|do|if|private|this|break|double|implements|protected|throw|byte|else|import|public|throws|case|enum|instanceof|return|transient|catch|extends|int|short|try|char|final|interface|static|void|class|finally|long|strictfp|volatile|const|float|native|super|while)([ \.\"\'\{\(;\xad&&lt;])/g,'&lt;b&gt;$1&lt;/b&gt;$2', // reserved words
	/([^:])\/\/(.*?)(&lt;br&gt;|&lt;\/P&gt;)/g,'$1&lt;i&gt;//$2&lt;/i&gt;$3', // comments
	/\/\*(.*?)\*\//g,'&lt;i&gt;/*$1*/&lt;/i&gt;' // comments
],
	javascript : [
	/([\"\'].*?[\"\'])/g,'&lt;s&gt;$1&lt;/s&gt;', // strings
	/(break|continue|do|for|import|new|this|void|case|default|else|function|in|return|typeof|while|comment|delete|export|if|label|switch|var|with|catch|boolean|byte|int|short|try|false|throws|null|true|goto)([ \.\"\'\{\(;\xad&&lt;])/g,'&lt;b&gt;$1&lt;/b&gt;$2', // reserved words
	/(alert|isNaN|parent|array|parseFloat|parseInt|blur|clearTimeout|prompt|prototype|close|confirm|length|Date|location|scroll|Math|document|element|name|self|elements|setTimeout|navigator|status|String|escape|Number|submit|eval|Object|event|onblur|text|focus|onerror|onfocus|top|onload|toString|onunload|unescape|open|opener|valueOf|window)/g,'&lt;u&gt;$1&lt;/u&gt;$2', // special words
	/([^:])\/\/(.*?)(&lt;br&gt;|&lt;\/P&gt;)/g,'$1&lt;i&gt;//$2&lt;/i&gt;$3', // comments
	/\/\*(.*?)\*\//g,'&lt;i&gt;/*$1*/&lt;/i&gt;' // comments
],
	php : [
	/(&lt;[^!\?]*?&gt;)/g,'&lt;b&gt;$1&lt;/b&gt;', // all tags
	/(&lt;style.*?&gt;)(.*?)(&lt;\/style&gt;)/g,'&lt;em&gt;$1&lt;/em&gt;&lt;em&gt;$2&lt;/em&gt;&lt;em&gt;$3&lt;/em&gt;', // style tags
	/(&lt;script.*?&gt;)(.*?)(&lt;\/script&gt;)/g,'&lt;u&gt;$1&lt;/u&gt;&lt;u&gt;$2&lt;/u&gt;&lt;u&gt;$3&lt;/u&gt;', // script tags
	/([\"\'].*?[\"\'])/g,'&lt;s&gt;$1&lt;/s&gt;', // strings
	/(&lt;\?.*?\?&gt;)/g,'&lt;strong&gt;$1&lt;/strong&gt;', // php tags	
	/(&lt;\?php|\?&gt;)/g,'&lt;cite&gt;$1&lt;/cite&gt;', // php tags		
	/(\$.*?)([ \)\(\[\{\+\-\*\/&!\|%=;])/g,'&lt;var&gt;$1&lt;/var&gt;$2',
	/(and|or|xor|__FILE__|exception|__LINE__|array|as|break|case|class|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|for|foreach|function|global|if|include|include_once|isset|list|new|print|require|require_once|return|static|switch|unset|use|var|while|__FUNCTION__|__CLASS__|__METHOD__|final|php_user_filter|interface|implements|extends|public|private|protected|abstract|clone|try|catch|throw|this)([ \.\"\'\{\(;\xad&&lt;])/g,'&lt;ins&gt;$1&lt;/ins&gt;$2', // reserved words
	/([^:])\/\/(.*?)(&lt;br&gt;|&lt;\/P&gt;)/g,'$1&lt;i&gt;//$2&lt;/i&gt;$3', // php comments
	/\/\*(.*?)\*\//g,'&lt;i&gt;/*$1*/&lt;/i&gt;', // php comments
	/(&lt;!--.*?--&gt.)/g,'&lt;big&gt;$1&lt;/big&gt;' // html comments 
],
	html : [
	/(&lt;[^!]*?&gt;)/g,'&lt;b&gt;$1&lt;/b&gt;', // all tags
	/(&lt;style.*?&gt;)(.*?)(&lt;\/style&gt;)/g,'&lt;em&gt;$1&lt;/em&gt;&lt;em&gt;$2&lt;/em&gt;&lt;em&gt;$3&lt;/em&gt;', // style tags
	/(&lt;script.*?&gt;)(.*?)(&lt;\/script&gt;)/g,'&lt;u&gt;$1&lt;/u&gt;&lt;u&gt;$2&lt;/u&gt;&lt;u&gt;$3&lt;/u&gt;', // script tags
	/=(["'].*?["'])/g,'=&lt;s&gt;$1&lt;/s&gt;', // atributes
	/(&lt;!--.*?--&gt.)/g,'&lt;i&gt;$1&lt;/i&gt;' // comments 
],
	text : [
] }

onload = function() {
	RTSH.initialize();
}
</pre>
</body>
</html>
